#!/usr/bin/env python3
"""
DataPlexus数据同步功能完整安装脚本
包含阶段1-5的所有功能安装和测试
"""

import asyncio
import sys
import os
import subprocess
import json
from pathlib import Path
from typing import Dict, Any, List

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

from app.core.config import settings
from app.core.logger import logger


class SyncModuleInstaller:
    """数据同步模块安装器"""
    
    def __init__(self):
        self.project_root = project_root
        self.scripts_dir = self.project_root / "scripts"
        self.backend_dir = self.project_root / "backend"
        self.frontend_dir = self.project_root / "frontend"
        
        self.installation_steps = [
            ("检查系统环境", self.check_environment),
            ("安装Python依赖", self.install_python_dependencies),
            ("创建数据库表", self.create_database_tables),
            ("初始化权限和路由", self.initialize_permissions),
            ("安装前端依赖", self.install_frontend_dependencies),
            ("构建前端资源", self.build_frontend),
            ("测试后端功能", self.test_backend),
            ("测试前端功能", self.test_frontend),
            ("性能测试", self.performance_test),
            ("生成安装报告", self.generate_report)
        ]
        
        self.results = {}
    
    async def run_installation(self):
        """运行完整安装流程"""
        logger.info("开始DataPlexus数据同步功能完整安装...")
        
        total_steps = len(self.installation_steps)
        
        for i, (step_name, step_func) in enumerate(self.installation_steps, 1):
            print(f"\n{'='*60}")
            print(f"步骤 {i}/{total_steps}: {step_name}")
            print(f"{'='*60}")
            
            try:
                result = await step_func()
                self.results[step_name] = {
                    'success': True,
                    'result': result,
                    'error': None
                }
                print(f"✅ {step_name} - 完成")
                
            except Exception as e:
                self.results[step_name] = {
                    'success': False,
                    'result': None,
                    'error': str(e)
                }
                print(f"❌ {step_name} - 失败: {e}")
                
                # 询问是否继续
                if not self._ask_continue():
                    break
        
        # 显示最终结果
        self._show_final_results()
    
    async def check_environment(self) -> Dict[str, Any]:
        """检查系统环境"""
        results = {}
        
        # 检查Python版本
        python_version = sys.version_info
        results['python_version'] = f"{python_version.major}.{python_version.minor}.{python_version.micro}"
        
        if python_version < (3, 8):
            raise Exception(f"Python版本过低，需要3.8+，当前版本: {results['python_version']}")
        
        # 检查Node.js
        try:
            node_result = subprocess.run(['node', '--version'], capture_output=True, text=True)
            results['node_version'] = node_result.stdout.strip()
        except FileNotFoundError:
            raise Exception("Node.js未安装，请先安装Node.js")
        
        # 检查npm
        try:
            npm_result = subprocess.run(['npm', '--version'], capture_output=True, text=True)
            results['npm_version'] = npm_result.stdout.strip()
        except FileNotFoundError:
            raise Exception("npm未安装，请先安装npm")
        
        # 检查MySQL连接
        try:
            from app.core.database import AsyncSessionLocal
            async with AsyncSessionLocal() as db:
                await db.execute("SELECT 1")
            results['database_connection'] = 'OK'
        except Exception as e:
            raise Exception(f"数据库连接失败: {e}")
        
        return results
    
    async def install_python_dependencies(self) -> Dict[str, Any]:
        """安装Python依赖"""
        dependencies = [
            'kafka-python',
            'aiohttp',
            'psutil',
            'aiomysql',
            'asyncpg'
        ]
        
        results = {}
        
        for dep in dependencies:
            try:
                result = subprocess.run([
                    sys.executable, '-m', 'pip', 'install', dep
                ], capture_output=True, text=True, cwd=self.project_root)
                
                if result.returncode == 0:
                    results[dep] = 'installed'
                else:
                    results[dep] = f'failed: {result.stderr}'
                    
            except Exception as e:
                results[dep] = f'error: {e}'
        
        return results
    
    async def create_database_tables(self) -> Dict[str, Any]:
        """创建数据库表"""
        sql_script = self.scripts_dir / "create_sync_tables.sql"
        
        if not sql_script.exists():
            raise Exception(f"SQL脚本不存在: {sql_script}")
        
        # 执行SQL脚本
        cmd = [
            'mysql',
            '-h', settings.DB_HOST,
            '-P', str(settings.DB_PORT),
            '-u', settings.DB_USER,
            f'-p{settings.DB_PASSWORD}',
            settings.DB_NAME,
            '-e', f'source {sql_script}'
        ]
        
        result = subprocess.run(cmd, capture_output=True, text=True, cwd=self.project_root)
        
        if result.returncode != 0:
            raise Exception(f"创建数据库表失败: {result.stderr}")
        
        # 验证表创建
        from app.core.database import AsyncSessionLocal
        async with AsyncSessionLocal() as db:
            tables_result = await db.execute("""
                SELECT TABLE_NAME 
                FROM information_schema.tables 
                WHERE table_schema = %s AND table_name LIKE 'dp_sync%'
            """, (settings.DB_NAME,))
            
            tables = [row[0] for row in tables_result.fetchall()]
        
        return {
            'created_tables': tables,
            'table_count': len(tables)
        }
    
    async def initialize_permissions(self) -> Dict[str, Any]:
        """初始化权限和路由"""
        permission_script = self.scripts_dir / "init_sync_permissions.py"
        
        if not permission_script.exists():
            raise Exception(f"权限初始化脚本不存在: {permission_script}")
        
        result = subprocess.run([
            sys.executable, str(permission_script)
        ], capture_output=True, text=True, cwd=self.project_root)
        
        if result.returncode != 0:
            raise Exception(f"权限初始化失败: {result.stderr}")
        
        return {'status': 'completed', 'output': result.stdout}
    
    async def install_frontend_dependencies(self) -> Dict[str, Any]:
        """安装前端依赖"""
        if not self.frontend_dir.exists():
            raise Exception("前端目录不存在")
        
        result = subprocess.run([
            'npm', 'install'
        ], capture_output=True, text=True, cwd=self.frontend_dir)
        
        if result.returncode != 0:
            raise Exception(f"前端依赖安装失败: {result.stderr}")
        
        return {'status': 'completed'}
    
    async def build_frontend(self) -> Dict[str, Any]:
        """构建前端资源"""
        result = subprocess.run([
            'npm', 'run', 'build'
        ], capture_output=True, text=True, cwd=self.frontend_dir)
        
        if result.returncode != 0:
            # 构建失败不是致命错误，只是警告
            return {'status': 'warning', 'message': 'Frontend build failed, but installation can continue'}
        
        return {'status': 'completed'}
    
    async def test_backend(self) -> Dict[str, Any]:
        """测试后端功能"""
        test_script = self.scripts_dir / "test_sync_engine.py"
        
        if not test_script.exists():
            raise Exception(f"测试脚本不存在: {test_script}")
        
        result = subprocess.run([
            sys.executable, str(test_script)
        ], capture_output=True, text=True, cwd=self.project_root)
        
        return {
            'exit_code': result.returncode,
            'stdout': result.stdout,
            'stderr': result.stderr,
            'status': 'passed' if result.returncode == 0 else 'failed'
        }
    
    async def test_frontend(self) -> Dict[str, Any]:
        """测试前端功能"""
        # 检查前端文件是否存在
        required_files = [
            'src/pages/SyncTaskManagement.tsx',
            'src/pages/SyncExecutionMonitor.tsx',
            'src/components/SyncTaskForm.tsx',
            'src/services/syncApi.ts',
            'src/types/sync.ts'
        ]
        
        missing_files = []
        existing_files = []
        
        for file_path in required_files:
            full_path = self.frontend_dir / file_path
            if full_path.exists():
                existing_files.append(file_path)
            else:
                missing_files.append(file_path)
        
        return {
            'existing_files': existing_files,
            'missing_files': missing_files,
            'status': 'passed' if not missing_files else 'warning'
        }
    
    async def performance_test(self) -> Dict[str, Any]:
        """性能测试"""
        try:
            # 测试性能监控器
            from app.utils.performance_monitor import performance_monitor
            
            # 启动监控
            await performance_monitor.start_monitoring(interval=0.1)
            
            # 模拟一些工作负载
            await asyncio.sleep(1)
            
            # 获取统计信息
            stats = performance_monitor.get_system_metrics_summary(last_n_minutes=1)
            
            # 停止监控
            await performance_monitor.stop_monitoring()
            
            return {
                'performance_monitor': 'working',
                'stats_sample': stats,
                'status': 'passed'
            }
            
        except Exception as e:
            return {
                'performance_monitor': 'failed',
                'error': str(e),
                'status': 'warning'
            }
    
    async def generate_report(self) -> Dict[str, Any]:
        """生成安装报告"""
        report = {
            'installation_time': asyncio.get_event_loop().time(),
            'total_steps': len(self.installation_steps),
            'successful_steps': sum(1 for r in self.results.values() if r['success']),
            'failed_steps': sum(1 for r in self.results.values() if not r['success']),
            'details': self.results
        }
        
        # 保存报告到文件
        report_file = self.project_root / "sync_installation_report.json"
        with open(report_file, 'w', encoding='utf-8') as f:
            json.dump(report, f, indent=2, ensure_ascii=False, default=str)
        
        return {
            'report_file': str(report_file),
            'summary': {
                'total_steps': report['total_steps'],
                'successful_steps': report['successful_steps'],
                'failed_steps': report['failed_steps']
            }
        }
    
    def _ask_continue(self) -> bool:
        """询问是否继续"""
        try:
            response = input("\n是否继续安装？(y/N): ").strip().lower()
            return response in ['y', 'yes', '是']
        except KeyboardInterrupt:
            return False
    
    def _show_final_results(self):
        """显示最终结果"""
        print(f"\n{'='*60}")
        print("安装完成！")
        print(f"{'='*60}")
        
        successful = sum(1 for r in self.results.values() if r['success'])
        total = len(self.results)
        
        print(f"总步骤: {total}")
        print(f"成功: {successful}")
        print(f"失败: {total - successful}")
        
        if successful == total:
            print("\n🎉 所有步骤都成功完成！")
            print("\n下一步操作：")
            print("1. 启动后端服务: uvicorn app.main:app --reload")
            print("2. 启动前端服务: cd frontend && npm start")
            print("3. 访问 http://localhost:3000/sync/tasks 测试同步功能")
        else:
            print("\n⚠️  部分步骤失败，请检查错误信息并手动修复")
            
            for step_name, result in self.results.items():
                if not result['success']:
                    print(f"❌ {step_name}: {result['error']}")


async def main():
    """主函数"""
    installer = SyncModuleInstaller()
    
    try:
        await installer.run_installation()
    except KeyboardInterrupt:
        print("\n⚠️  安装被用户中断")
        sys.exit(1)
    except Exception as e:
        print(f"\n❌ 安装过程中发生异常: {e}")
        sys.exit(1)


if __name__ == "__main__":
    asyncio.run(main())
